// 版权所有2009年围棋作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package tls

import (
	"bytes"
	"container/list"
	"context"
	"crypto"
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha512"
	"crypto/x509"
	"errors"
	"fmt"
	"io"
	"net"
	"strings"
	"sync"
	"time"
)

const (
	VersionTLS10 = 0x0301
	VersionTLS11 = 0x0302
	VersionTLS12 = 0x0303
	VersionTLS13 = 0x0304

	// 不推荐使用：SSLv3已被加密破坏，不再使用
	// 由此软件包支持。见golang.org/issue/32716。
	VersionSSL30 = 0x0300
)

const (
	maxPlaintext       = 16384        // 最大明文有效负载长度
	maxCiphertext      = 16384 + 2048 // 最大密文有效负载长度
	maxCiphertextTLS13 = 16384 + 256  // TLS 1.3中的最大密文长度
	recordHeaderLen    = 5            // 记录头长度
	maxHandshake       = 65536        // 我们支持的最大握手（协议最大容量为16 MB）
	maxUselessRecords  = 16           // 连续非前进记录的最大数量
)

// TLS记录类型。
type recordType uint8

const (
	recordTypeChangeCipherSpec recordType = 20
	recordTypeAlert            recordType = 21
	recordTypeHandshake        recordType = 22
	recordTypeApplicationData  recordType = 23
)

// TLS握手消息类型。
const (
	typeHelloRequest        uint8 = 0
	typeClientHello         uint8 = 1
	typeServerHello         uint8 = 2
	typeNewSessionTicket    uint8 = 4
	typeEndOfEarlyData      uint8 = 5
	typeEncryptedExtensions uint8 = 8
	typeCertificate         uint8 = 11
	typeServerKeyExchange   uint8 = 12
	typeCertificateRequest  uint8 = 13
	typeServerHelloDone     uint8 = 14
	typeCertificateVerify   uint8 = 15
	typeClientKeyExchange   uint8 = 16
	typeFinished            uint8 = 20
	typeCertificateStatus   uint8 = 22
	typeKeyUpdate           uint8 = 24
	typeNextProtocol        uint8 = 67  // 未分配IANA
	typeMessageHash         uint8 = 254 // 合成信息
)

// TLS压缩类型。
const (
	compressionNone uint8 = 0
)

// TLS分机号码
const (
	extensionServerName              uint16 = 0
	extensionStatusRequest           uint16 = 5
	extensionSupportedCurves         uint16 = 10 // TLS 1.3中支持的_组，见RFC 8446，第4.2.7节
	extensionSupportedPoints         uint16 = 11
	extensionSignatureAlgorithms     uint16 = 13
	extensionALPN                    uint16 = 16
	extensionSCT                     uint16 = 18
	extensionSessionTicket           uint16 = 35
	extensionPreSharedKey            uint16 = 41
	extensionEarlyData               uint16 = 42
	extensionSupportedVersions       uint16 = 43
	extensionCookie                  uint16 = 44
	extensionPSKModes                uint16 = 45
	extensionCertificateAuthorities  uint16 = 47
	extensionSignatureAlgorithmsCert uint16 = 50
	extensionKeyShare                uint16 = 51
	extensionRenegotiationInfo       uint16 = 0xff01
)

// TLS信令密码套件值
const (
	scsvRenegotiation uint16 = 0x00ff
)

// CurveID是椭圆曲线的TLS标识符类型。看见
// https:
// None
// 在TLS 1.3中，这种类型称为NamedGroup，但此时此库
// 仅支持基于椭圆曲线的组。见RFC 8446，第4.2.7节。
type CurveID uint16

const (
	CurveP256 CurveID = 23
	CurveP384 CurveID = 24
	CurveP521 CurveID = 25
	X25519    CurveID = 29
)

// TLS 1.3密钥共享。见RFC 8446，第4.2.8节。
type keyShare struct {
	group CurveID
	data  []byte
}

// TLS 1.3 PSK密钥交换模式。见RFC 8446，第4.2.9节。
const (
	pskModePlain uint8 = 0
	pskModeDHE   uint8 = 1
)

// TLS 1.3 PSK标识。可以是会话票证，也可以是对已保存会话的引用
// 一场见RFC 8446，第4.2.11节。
type pskIdentity struct {
	label               []byte
	obfuscatedTicketAge uint32
}

// TLS椭圆曲线点格式
// https:
const (
	pointFormatUncompressed uint8 = 0
)

// TLS CertificateStatusType（RFC 3546）
const (
	statusTypeOCSP uint8 = 1
)

// 证书类型（用于CertificateRequestsMSG）
const (
	certTypeRSASign   = 1
	certTypeECDSASign = 64 // ECDSA或EdDSA密钥，见RFC 8422第3节。
)

// 签名算法（用于内部信令）。从225开始，以避免与
// TLS 1.2代码点（RFC 5246，附录A.4.1），与之无关。
const (
	signaturePKCS1v15 uint8 = iota + 225
	signatureRSAPSS
	signatureECDSA
	signatureEd25519
)

// directSigning是一个标准的哈希值，表示没有预哈希
// 应该执行，并且输入应该直接签名。它是
// 与Ed25519签名方案关联的哈希函数。
var directSigning crypto.Hash = 0

// supportedSignatureAlgorithms包含用于
// 该代码在TLS 1.2+ClientHello和TLS 1.2中提供了支持+
// 认证请求。这两个字段合并以与TLS 1.3匹配。
// 请注意，在TLS 1.2中，ECDSA算法不限于P-256等。
var supportedSignatureAlgorithms = []SignatureScheme{
	PSSWithSHA256,
	ECDSAWithP256AndSHA256,
	Ed25519,
	PSSWithSHA384,
	PSSWithSHA512,
	PKCS1WithSHA256,
	PKCS1WithSHA384,
	PKCS1WithSHA512,
	ECDSAWithP384AndSHA384,
	ECDSAWithP521AndSHA512,
	PKCS1WithSHA1,
	ECDSAWithSHA1,
}

// helloRetryRequestRandom设置为ServerHello的随机值
// 表示该消息实际上是HelloRetryRequest。
var helloRetryRequestRandom = []byte{ // 见RFC 8446，第4.1.3节。
	0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
	0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
	0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
	0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
}

const (
	// 降级CanaryTLS12或降级CanaryTLS11嵌入到服务器中
	// 如果服务器能够
	// 谈判更高版本。见RFC 8446，第4.1.3节。
	downgradeCanaryTLS12 = "DOWNGRD\x01"
	downgradeCanaryTLS11 = "DOWNGRD\x00"
)

// TestingOnlyForceDowngrade Canary在测试中设置，以强制服务器端
// 包括降级金丝雀，即使它使用的是更高的支持版本。
var testingOnlyForceDowngradeCanary bool

// ConnectionState记录有关连接的基本TLS详细信息。
type ConnectionState struct {
	// Version是连接使用的TLS版本（例如VersionTLS12）。
	Version uint16

	// 如果握手已结束，则握手完成为真。
	HandshakeComplete bool

	// 如果此连接已从成功恢复，则DidResume为true
	// 具有会话票证或类似机制的上一个会话。
	DidResume bool

	// CipherSuite是为连接协商的密码套件（例如。
	// TLS_ECDHE_ECDSA_与_AES_128_GCM_SHA256，TLS_AES_128_GCM_SHA256）。
	CipherSuite uint16

	// NegotiatedProtocol是与ALPN协商的应用协议。
	NegotiatedProtocol string

	// NegotiatedProtocolismual用于表示双方的NPN谈判。
	// None
	// 不推荐：此值始终为true。
	NegotiatedProtocolIsMutual bool

	// ServerName是由发送的服务器名称指示扩展名的值
	// 客户。它在服务器端和客户端都可用。
	ServerName string

	// PeerCertificates是对等方在
	// 它们被发送的顺序。第一个元素是叶证书
	// 验证连接是否正确。
	// None
	// 在客户端，它不能为空。在服务器端，它可以是
	// 如果Config.ClientAuth不是requirenyClientCert或
	// 要求验证客户证书。
	PeerCertificates []*x509.Certificate

	// VerifiedChains是第一个元素所在的一个或多个链的列表
	// PeerCertificates[0]，最后一个元素来自Config.RootCAs（位于
	// 客户端）或Config.ClientCAs（在服务器端）。
	// None
	// 在客户端，如果Config.unsecureskipverify为false，则会设置它。在…上
	// 在服务器端，如果Config.ClientAuth是VerifyClientCertIfGiven，则会设置它
	// （且同行提供了证书）或要求验证ClientCert。
	VerifiedChains [][]*x509.Certificate

	// SignedCertificateTimestamps是由对等方提供的SCT列表
	// 通过TLS握手获取叶证书（如果有）。
	SignedCertificateTimestamps [][]byte

	// OCSPResponse是一个固定的在线证书状态协议（OCSP）
	// 对等方提供的叶证书响应（如果有）。
	OCSPResponse []byte

	// TLSUnique包含“tls唯一”通道绑定值（参见RFC 5929，
	// 第3节）。对于TLS 1.3连接和所有连接，该值为零
	// 恢复连接。
	// None
	// 不推荐：在某些情况下，此值可能不是唯一的
	// 连接到一个连接。参见RFC 5705和RFC 5705的安全注意事项部分
	// RFC 7627和https：
	TLSUnique []byte

	// ekm是一种通过ExportKeyingMaterial暴露的闭合。
	ekm func(label string, context []byte, length int) ([]byte, error)
}

// ExportKeyingMaterial以新格式返回导出的关键材质的长度字节
// 按照RFC 5705中的定义进行切片。如果上下文为nil，则不将其用作
// 种子。如果连接设置为允许通过重新协商
// 如果重新协商，此函数将返回一个错误。
func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
	return cs.ekm(label, context, length)
}

// ClientAuthType声明服务器将遵循的策略
// TLS客户端身份验证。
type ClientAuthType int

const (
	// NoClientCert表示不应请求任何客户端证书
	// 在握手过程中，如果发送了任何证书，则不会发送
	// 要核实。
	NoClientCert ClientAuthType = iota
	// RequestClientCert表示应请求客户端证书
	// 在握手过程中，但不要求客户端发送任何
	// 证书。
	RequestClientCert
	// RequireOnClientCert表示应请求客户端证书
	// 在握手过程中，至少需要一个证书
	// 由客户端发送，但该证书不要求有效。
	RequireAnyClientCert
	// VerifyClientCertifiven表示应请求客户端证书
	// 在握手过程中，但不要求客户端发送
	// 证明书如果客户端确实发送了证书，则需要
	// 有效的
	VerifyClientCertIfGiven
	// RequirementVerifyClientCert表示应请求客户端证书
	// 在握手过程中，至少需要一个有效证书
	// 由客户端发送。
	RequireAndVerifyClientCert
)

// requiresClientCert报告ClientAuthType是否需要客户端
// 需提供的证书。
func requiresClientCert(c ClientAuthType) bool {
	switch c {
	case RequireAnyClientCert, RequireAndVerifyClientCert:
		return true
	default:
		return false
	}
}

// ClientSessionState包含客户端恢复TLS所需的状态
// 会议。
type ClientSessionState struct {
	sessionTicket      []uint8               // 用于与服务器恢复会话的加密票证
	vers               uint16                // 为会话协商的TLS版本
	cipherSuite        uint16                // 为会议协商的Ciphersuite
	masterSecret       []byte                // 完全握手主密钥，或TLS 1.3恢复主密钥
	serverCertificates []*x509.Certificate   // 服务器提供的证书链
	verifiedChains     [][]*x509.Certificate // 我们为验证而构建的证书链
	receivedAt         time.Time             // 从服务器接收会话票证时
	ocspResponse       []byte                // 服务器提供的已装订OCSP响应
	scts               [][]byte              // 服务器提供的SCT

	// TLS 1.3字段。
	nonce  []byte    // 服务器发送的票证nonce，用于派生PSK
	useBy  time.Time // 服务器设置的票证生存期到期
	ageAdd uint32    // 发送票龄的随机模糊因子
}

// ClientSessionCache是可以使用的ClientSessionState对象的缓存
// 由客户端恢复与给定服务器的TLS会话。客户端会话缓存
// 实现应该期望从不同的服务器并发调用
// 戈罗季斯。在TLS 1.2之前，仅支持基于票证的恢复，而不支持基于票证的恢复
// 基于SessionID的恢复。在TLS1.3中，它们被合并到PSK模式中
// 通过此接口支持。
type ClientSessionCache interface {
	// Get搜索与给定键关联的ClientSessionState。
	// 返回时，如果找到一个，则ok为真。
	Get(sessionKey string) (session *ClientSessionState, ok bool)

	// Put使用给定的键将ClientSessionState添加到缓存中。可能吧
	// 如果TLS 1.3服务器提供
	// 不止一张会议票。如果使用nil*ClientSessionState调用，
	// 它应该删除缓存项。
	Put(sessionKey string, cs *ClientSessionState)
}

// go:generate stringer-type=SignatureScheme，CurveID，ClientAuthType-output=common_string.go

// SignatureScheme标识TLS支持的签名算法。看见
// RFC 8446，第4.2.3节。
type SignatureScheme uint16

const (
	// RSASSA-PKCS1-v1_5算法。
	PKCS1WithSHA256 SignatureScheme = 0x0401
	PKCS1WithSHA384 SignatureScheme = 0x0501
	PKCS1WithSHA512 SignatureScheme = 0x0601

	// 带有公钥加密的RSASSA-PSS算法。
	PSSWithSHA256 SignatureScheme = 0x0804
	PSSWithSHA384 SignatureScheme = 0x0805
	PSSWithSHA512 SignatureScheme = 0x0806

	// ECDSA算法。仅约束到TLS 1.3中的特定曲线。
	ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
	ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
	ECDSAWithP521AndSHA512 SignatureScheme = 0x0603

	// EdDSA算法。
	Ed25519 SignatureScheme = 0x0807

	// TLS 1.2的传统签名和哈希算法。
	PKCS1WithSHA1 SignatureScheme = 0x0201
	ECDSAWithSHA1 SignatureScheme = 0x0203
)

// ClientHelloInfo包含来自ClientHello消息的信息，以便
// 在GetCertificate和GetConfigForClient回调中指导应用程序逻辑。
type ClientHelloInfo struct {
	// CipherSuite列出了客户端支持的密码套件（例如。
	// TLS_AES_128_GCM_SHA256，TLS_ECDHE_ECDSA_与_AES_128_GCM_SHA256）。
	CipherSuites []uint16

	// ServerName指示客户端请求的服务器的名称
	// 为了支持虚拟主机。仅当
	// 客户正在使用SNI（参见RFC 4366第3.1节）。
	ServerName string

	// SupportedCurves列出客户端支持的椭圆曲线。
	// 仅当支持的椭圆曲线
	// 正在使用扩展（见RFC 4492，第5.1.1节）。
	SupportedCurves []CurveID

	// SupportedPoints列出客户端支持的点格式。
	// 仅当支持的点格式扩展名为
	// 正在使用（见RFC 4492，第5.1.2节）。
	SupportedPoints []uint8

	// SignatureSchemes列出客户端使用的签名和哈希方案
	// 愿意核实。SignatureSchemes仅当签名
	// 正在使用算法扩展（见RFC 5246，第7.4.1.4.1节）。
	SignatureSchemes []SignatureScheme

	// SupportedProtos列出了客户端支持的应用程序协议。
	// 仅当应用层协议
	// 正在使用协商扩展（见RFC 7301，第3.1节）。
	// None
	// 服务器可以通过在中设置Config.NextProtos来选择协议
	// GetConfigForClient返回值。
	SupportedProtos []string

	// SupportedVersions列出客户端支持的TLS版本。
	// 对于小于1.3的TLS版本，这是从最大
	// 由客户端公布的版本，因此值不是最大值
	// 如果使用，可能会被拒绝。
	SupportedVersions []uint16

	// Conn是连接的基础net.Conn。不读书
	// 来自或写信给此连接；这将导致TLS
	// 连接可能会失败。
	Conn net.Conn

	// 配置由GetCertificate或GetConfigForClient调用程序嵌入，
	// 用于支持证书。
	config *Config

	// ctx是正在进行的握手的上下文。
	ctx context.Context
}

// Context返回正在进行的握手的上下文。
// 此上下文是传递给HandshakeContext的上下文的子级，
// 如果有，则在握手结束时取消。
func (c *ClientHelloInfo) Context() context.Context {
	return c.ctx
}

// CertificateRequestInfo包含来自服务器
// CertificateRequest消息，用于请求证书和证明
// 来自客户端的控制。
type CertificateRequestInfo struct {
	// AcceptableCAs包含零个或多个DER编码的X.501
	// 杰出的名字。这些是根CA或中间CA的名称
	// 服务器希望返回的证书由其签名。一
	// 空切片表示服务器没有首选项。
	AcceptableCAs [][]byte

	// SignatureSchemes列出服务器使用的签名方案
	// 愿意核实。
	SignatureSchemes []SignatureScheme

	// Version是为此连接协商的TLS版本。
	Version uint16

	// ctx是正在进行的握手的上下文。
	ctx context.Context
}

// Context返回正在进行的握手的上下文。
// 此上下文是传递给HandshakeContext的上下文的子级，
// 如果有，则在握手结束时取消。
func (c *CertificateRequestInfo) Context() context.Context {
	return c.ctx
}

// 重新协商支持列举了TLS的不同支持级别
// 重新谈判。TLS重新协商是执行后续协议的行为
// 在第一次连接之后进行握手。这大大使问题复杂化
// 状态机是众多微妙安全的来源
// 问题。不支持启动重新协商，但支持
// 可以启用接受重新协商请求。
// None
// 即使启用，服务器也可能不会在握手之间更改其标识
// （即叶证书必须相同）。此外，并发
// 不允许握手和应用程序数据流，因此可以重新协商
// 仅用于与重新协商同步的协议，例如
// HTTPS。
// None
// TLS 1.3中未定义重新协商。
type RenegotiationSupport int

const (
	// 重新谈判从不禁止重新谈判。
	RenegotiateNever RenegotiationSupport = iota

	// 重新协商EastClient允许远程服务器请求
	// 每个连接重新协商一次。
	RenegotiateOnceAsClient

	// 重新协商FreelyAsClient允许远程服务器重复协商
	// 请求重新谈判。
	RenegotiateFreelyAsClient
)

// 配置结构用于配置TLS客户端或服务器。
// 在将一个传递给TLS函数后，不能
// 被改进的。配置可以重用；tls软件包也不会
// 修改它。
type Config struct {
	// Rand为nonce和RSA致盲提供了熵源。
	// 如果Rand为nil，则TLS在包中使用加密随机读取器
	// 加密/兰德。
	// 读卡器必须能够安全地供多个goroutine使用。
	Rand io.Reader

	// Time将当前时间作为自历元以来的秒数返回。
	// 如果Time为nil，则TLS使用Time.Now。
	Time func() time.Time

	// 证书包含一个或多个要呈现给用户的证书链
	// 连接的另一侧。第一个与
	// 自动选择对等方的需求。
	// None
	// 服务器配置必须设置证书GetCertificate或
	// GetConfigForClient。进行客户端身份验证的客户端可以设置
	// 证书或GetClientCertificate。
	// None
	// 注意：如果有多个证书，并且它们没有
	// 可选字段叶集，证书选择将导致重大错误
	// 每次握手的性能成本。
	Certificates []Certificate

	// NameToCertificate从证书名称映射到
	// 证书。请注意，证书名称的格式可以是
	// “*.example.com”等不必是域名。
	// None
	// 不推荐使用：NameToCertificate仅允许关联单个
	// 具有给定名称的证书。将此字段保留为零以使库
	// 从证书中选择第一个兼容链。
	NameToCertificate map[string]*Certificate

	// GetCertificate返回基于给定
	// ClientHelloInfo。只有当客户提供SNI时才会调用它
	// 信息或证书是否为空。
	// None
	// 如果GetCertificate为nil或返回nil，则证书为
	// 从NameToCertificate检索。如果NameToCertificate为零，则
	// 将使用证书的最佳元素。
	GetCertificate func(*ClientHelloInfo) (*Certificate, error)

	// 如果不是nil，则当服务器请求
	// 来自客户端的证书。如果设置，则证书的内容将
	// 被忽视。
	// None
	// 如果GetClientCertificate返回错误，则握手将被取消
	// 已中止，将返回该错误。否则
	// GetClientCertificate必须返回非nil证书。如果
	// 证书。证书为空，则不会向发送任何证书
	// 服务器。如果服务器无法接受，则可能会中止
	// 握手。
	// None
	// GetClientCertificate可能会被多次调用
	// 重新协商或TLS 1.3正在使用时的连接。
	GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)

	// 如果不是nil，则在调用ClientHello之后调用GetConfigForClient
	// 从客户那里收到的。它可能会返回一个非nil配置，以便
	// 更改将用于处理此连接的配置。如果
	// 返回的配置为nil，将使用原始配置。这个
	// 随后可能不会修改此回调返回的配置。
	// None
	// 如果GetConfigForClient为nil，则传递给服务器（）的配置将为
	// 用于所有连接。
	// None
	// 如果在返回的配置上显式设置了SessionTicketKey，或者
	// 已对返回的配置调用SetSessionTicketKeys，这些键将
	// 被使用。否则，将使用原始配置键（并且可能
	// 旋转（如果它们是自动管理的）。
	GetConfigForClient func(*ClientHelloInfo) (*Config, error)

	// VerifyPeerCertificate，如果不是nil，则在正常后调用
	// TLS客户端或服务器的证书验证。信息技术
	// 接收对等方提供的原始ASN.1证书，并且
	// 正常处理发现的任何已验证链。如果它返回一个
	// 非零错误，握手被中止并导致该错误。
	// None
	// 如果正常验证失败，则握手将在之前中止
	// 考虑到这次回调。如果通过禁用正常验证
	// 设置UnsecureSkipVerify，或（对于服务器）在ClientAuth为
	// RequestClientCert或RequireOnClientCert，则此回调将
	// 将被考虑，但verifiedChains参数将始终为零。
	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error

	// 如果不是nil，则在正常证书之后调用VerifyConnection
	// TLS客户机验证和验证PeerCertificate后
	// 或服务器。如果它返回一个非零错误，握手将中止
	// 结果就是这个错误。
	// None
	// 如果正常验证失败，则握手将在之前中止
	// 考虑到这次回调。此回调将对所有连接运行
	// 无论不安全的SkipVerify或ClientAuth设置如何。
	VerifyConnection func(ConnectionState) error

	// RootCAs定义根证书授权的集合
	// 客户端在验证服务器证书时使用的。
	// 如果RootCAs为nil，则TLS使用主机的根CA集。
	RootCAs *x509.CertPool

	// NextProtos是受支持的应用程序级协议的列表，以
	// 优先顺序。如果两个对等方都支持ALPN，则选择
	// 协议将是此列表中的一个，并且连接将失败
	// 如果没有相互支持的协议。如果NextProtos为空
	// 或者对等方不支持ALPN，则连接将成功，并且
	// ConnectionState.NegotiatedProtocol将为空。
	NextProtos []string

	// ServerName用于验证返回的服务器上的主机名
	// 证书，除非给出了不安全的SKIPVERIFY。它也包括在内
	// 在客户端的握手中支持虚拟主机，除非
	// IP地址。
	ServerName string

	// ClientAuth确定服务器的策略
	// TLS客户端身份验证。默认值为NoClientCert。
	ClientAuth ClientAuthType

	// ClientCAs定义根证书颁发机构的集合
	// 服务器在需要时用于验证客户端证书的
	// 根据ClientAuth的政策。
	ClientCAs *x509.CertPool

	// UnsecureSkipVerify控制客户端是否验证服务器的
	// 证书链和主机名。如果UnsecureSkipVerify为true，则加密/tls
	// 接受服务器提供的任何证书以及其中的任何主机名
	// 证明书在此模式下，TLS易受中间机器的影响
	// 攻击，除非使用自定义验证。这应该只用于
	// 测试或与VerifyConnection或VerifyPeerCertificate结合使用。
	InsecureSkipVerify bool

	// CipherSuite是已启用的TLS 1.0–1.2密码套件的列表。秩序
	// 该列表将被忽略。请注意，TLS 1.3密码套件是不可配置的。
	// None
	// 如果CipherSuite为零，则使用安全默认列表。默认密码
	// 套房可能会随着时间的推移而改变。
	CipherSuites []uint16

	// PreferServerCipherSuite是一个旧字段，不起作用。
	// None
	// 它用于控制服务器是否遵循客户机的或
	// 服务器的首选项。服务器现在选择相互支持的最佳服务器
	// 基于考虑推断客户端的逻辑的密码套件
	// 硬件、服务器硬件和安全性。
	// None
	// 已弃用：已忽略PreferServerCipherSuite。
	PreferServerCipherSuites bool

	// SessionTicketsDisabled可设置为true以禁用会话票证和
	// PSK（恢复）支持。请注意，在客户端上，会话票证支持是
	// 如果ClientSessionCache为nil，也将禁用。
	SessionTicketsDisabled bool

	// TLS服务器使用SessionTicketKey来提供会话恢复。
	// 参见RFC 5077和RFC 8446的PSK模式。如果为零，它将被填充
	// 在第一次服务器握手之前使用随机数据。
	// None
	// 不推荐：如果此字段保留为零，则会话票证密钥将被删除
	// 每天自动旋转，七天后下降。对于
	// 自定义旋转计划或同步正在运行的服务器
	// 终止同一主机的连接时，请使用SetSessionTicketKeys。
	SessionTicketKey [32]byte

	// ClientSessionCache是TLS的ClientSessionState项的缓存
	// 复会。它只供客户端使用。
	ClientSessionCache ClientSessionCache

	// MinVersion包含可接受的最低TLS版本。
	// 如果为零，则TLS 1.0当前为最小值。
	MinVersion uint16

	// MaxVersion包含可接受的最大TLS版本。
	// 如果为零，则使用此软件包支持的最大版本，
	// 目前是TLS 1.3。
	MaxVersion uint16

	// CurvePreferences包含将在中使用的椭圆曲线
	// 按优先顺序进行的ECDHE握手。如果为空，则默认值为
	// 被使用。客户端将使用第一个首选项作为
	// 其在TLS 1.3中的主要份额。这在将来可能会改变。
	CurvePreferences []CurveID

	// DynamicRecordSizingDisabled禁用TLS记录的自适应大小调整。
	// 如果为true，则始终使用可能的最大TLS记录大小。什么时候
	// 错误，可能会调整TLS记录的大小，以尝试
	// 改善延迟。
	DynamicRecordSizingDisabled bool

	// 重新协商控制支持何种类型的重新协商。
	// 默认值none适用于绝大多数应用程序。
	Renegotiation RenegotiationSupport

	// KeyLogWriter可以选择指定TLS主机密的目标
	// NSS密钥日志格式，可用于允许外部程序
	// 例如Wireshark来解密TLS连接。
	// 请参阅https:
	// 使用KeyLogWriter会损害安全性，因此只应
	// 用于调试。
	KeyLogWriter io.Writer

	// 互斥锁保护sessionTicketKeys和autoSessionTicketKeys。
	mutex sync.RWMutex
	// sessionTicketKeys包含零个或多个票证密钥。如果设置，则表示
	// 使用SessionTicketKey或SetSessionTicketKey设置键。这个
	// 第一个键用于新的票证，任何后续键都可以用于
	// 解密旧票。切片内容不受互斥锁的保护
	// 它们是不变的。
	sessionTicketKeys []ticketKey
	// autoSessionTicketKeys与sessionTicketKeys类似，但属于
	// 自动旋转逻辑。请参阅Config.ticketKeys。
	autoSessionTicketKeys []ticketKey
}

const (
	// ticketKeyNameLen是前缀为的标识符的字节数
	// 加密的会话票证，用于标识用于加密的密钥。
	ticketKeyNameLen = 16

	// ticketKeyLifetime是票证密钥保持有效并可用于
	// 恢复客户端连接。
	ticketKeyLifetime = 7 * 24 * time.Hour // 7天

	// ticketKeyRotation是服务器应旋转会话票证密钥的频率
	// 这是用来买新票的。
	ticketKeyRotation = 24 * time.Hour
)

// ticketKey是会话票证密钥的内部表示形式。
type ticketKey struct {
	// keyName是一个不透明的字节字符串，用于标识会话
	// 车票钥匙。它在每一次会议记录中都以明文形式公开。
	keyName [ticketKeyNameLen]byte
	aesKey  [16]byte
	hmacKey [16]byte
	// created是创建此票证密钥的时间。请参阅Config.ticketKeys。
	created time.Time
}

// ticketKeyFromBytes从会话的外部表示形式转换
// 票证钥匙到票证钥匙。在外部，会话票证密钥是32个随机密钥
// 字节，此函数将其扩展为足够的名称和密钥材料。
func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
	hashed := sha512.Sum512(b[:])
	copy(key.keyName[:], hashed[:ticketKeyNameLen])
	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
	key.created = c.time()
	return key
}

// maxSessionTicketLifetime是TLS 1.3会话允许的最大生存期
// 票，以及我们为我们发送的票设定的生命周期。
const maxSessionTicketLifetime = 7 * 24 * time.Hour

// Clone返回c的浅克隆，如果c为nil，则返回nil。克隆一个配置是安全的
// 由TLS客户端或服务器同时使用。
func (c *Config) Clone() *Config {
	if c == nil {
		return nil
	}
	c.mutex.RLock()
	defer c.mutex.RUnlock()
	return &Config{
		Rand:                        c.Rand,
		Time:                        c.Time,
		Certificates:                c.Certificates,
		NameToCertificate:           c.NameToCertificate,
		GetCertificate:              c.GetCertificate,
		GetClientCertificate:        c.GetClientCertificate,
		GetConfigForClient:          c.GetConfigForClient,
		VerifyPeerCertificate:       c.VerifyPeerCertificate,
		VerifyConnection:            c.VerifyConnection,
		RootCAs:                     c.RootCAs,
		NextProtos:                  c.NextProtos,
		ServerName:                  c.ServerName,
		ClientAuth:                  c.ClientAuth,
		ClientCAs:                   c.ClientCAs,
		InsecureSkipVerify:          c.InsecureSkipVerify,
		CipherSuites:                c.CipherSuites,
		PreferServerCipherSuites:    c.PreferServerCipherSuites,
		SessionTicketsDisabled:      c.SessionTicketsDisabled,
		SessionTicketKey:            c.SessionTicketKey,
		ClientSessionCache:          c.ClientSessionCache,
		MinVersion:                  c.MinVersion,
		MaxVersion:                  c.MaxVersion,
		CurvePreferences:            c.CurvePreferences,
		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
		Renegotiation:               c.Renegotiation,
		KeyLogWriter:                c.KeyLogWriter,
		sessionTicketKeys:           c.sessionTicketKeys,
		autoSessionTicketKeys:       c.autoSessionTicketKeys,
	}
}

// deprecatedSessionTicketKey设置为SessionTicketKey的前缀（如果为）
// 随机向后兼容，但未使用。
var deprecatedSessionTicketKey = []byte("DEPRECATED")

// initLegacySessionTicketKeyRLocked确保保留旧的SessionTicketKey字段
// 如果为空，则为随机化，否则将从中填充sessionTicketKeys。
func (c *Config) initLegacySessionTicketKeyRLocked() {
	// 如果SessionTicketKey已定义为不推荐使用的字符串，则不要写入，
	// 或者由用户定义，但已设置sessionTicketKeys。
	if c.SessionTicketKey != [32]byte{} &&
		(bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) {
		return
	}

	// 我们需要写入一些数据，所以获取一个独占锁并重新检查任何条件。
	c.mutex.RUnlock()
	defer c.mutex.RLock()
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if c.SessionTicketKey == [32]byte{} {
		if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
			panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err))
		}
		// 在开头写下不推荐使用的前缀，这样我们就知道我们创建了
		// 信息技术此带有不推荐前缀的键未用作实际的
		// 会话票证密钥，并且仅在应用程序
		// 出于某种原因重复使用它。
		copy(c.SessionTicketKey[:], deprecatedSessionTicketKey)
	} else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 {
		c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)}
	}

}

// ticketKeys返回此连接的ticketKeys。
// 如果configForClient已显式设置密钥，则这些密钥将
// 被退回。否则，将使用c上的键，并且
// 如果自动管理，则可以旋转。
// 在轮换期间，任何过期的会话票证密钥都将从中删除
// c、 sessionTicketKeys。如果会话票证密钥当前为
// 加密票证（即c.sessionTicketKeys中的第一个票证密钥）
// 不是新的，则将创建新的会话票证密钥
// 已创建并在c.sessionTicketKeys之前添加。
func (c *Config) ticketKeys(configForClient *Config) []ticketKey {
	// 如果ConfigForClient回调返回显式设置为
	// 键，使用这些，否则只需使用原始配置。
	if configForClient != nil {
		configForClient.mutex.RLock()
		if configForClient.SessionTicketsDisabled {
			return nil
		}
		configForClient.initLegacySessionTicketKeyRLocked()
		if len(configForClient.sessionTicketKeys) != 0 {
			ret := configForClient.sessionTicketKeys
			configForClient.mutex.RUnlock()
			return ret
		}
		configForClient.mutex.RUnlock()
	}

	c.mutex.RLock()
	defer c.mutex.RUnlock()
	if c.SessionTicketsDisabled {
		return nil
	}
	c.initLegacySessionTicketKeyRLocked()
	if len(c.sessionTicketKeys) != 0 {
		return c.sessionTicketKeys
	}
	// 对于钥匙足够新鲜的常见情况，快速路径。
	if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation {
		return c.autoSessionTicketKeys
	}

	// autoSessionTicketKeys由自动旋转管理。
	c.mutex.RUnlock()
	defer c.mutex.RLock()
	c.mutex.Lock()
	defer c.mutex.Unlock()
	// 重新检查条件，以防在获得新锁后发生变化。
	if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
		var newKey [32]byte
		if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil {
			panic(fmt.Sprintf("unable to generate random session ticket key: %v", err))
		}
		valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1)
		valid = append(valid, c.ticketKeyFromBytes(newKey))
		for _, k := range c.autoSessionTicketKeys {
			// 在旋转当前键的同时，也删除所有过期的键。
			if c.time().Sub(k.created) < ticketKeyLifetime {
				valid = append(valid, k)
			}
		}
		c.autoSessionTicketKeys = valid
	}
	return c.autoSessionTicketKeys
}

// SetSessionTicketKeys更新服务器的会话票证密钥。
// None
// 创建新票证时将使用第一个键，而可以使用所有键
// 用于解密票据。在
// 服务器正在运行以旋转会话票证密钥。功能
// 如果钥匙是空的，它会死机。
// None
// 调用此函数将关闭自动会话票证密钥旋转。
// None
// 如果多个服务器正在终止同一主机的连接，则它们应该
// 它们都有相同的会话票证密钥。如果会话票证密钥泄漏，
// 以前记录的和将来使用这些密钥的TLS连接可能是
// 妥协的。
func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
	if len(keys) == 0 {
		panic("tls: keys must have at least one key")
	}

	newKeys := make([]ticketKey, len(keys))
	for i, bytes := range keys {
		newKeys[i] = c.ticketKeyFromBytes(bytes)
	}

	c.mutex.Lock()
	c.sessionTicketKeys = newKeys
	c.mutex.Unlock()
}

func (c *Config) rand() io.Reader {
	r := c.Rand
	if r == nil {
		return rand.Reader
	}
	return r
}

func (c *Config) time() time.Time {
	t := c.Time
	if t == nil {
		t = time.Now
	}
	return t()
}

func (c *Config) cipherSuites() []uint16 {
	if c.CipherSuites != nil {
		return c.CipherSuites
	}
	return defaultCipherSuites
}

var supportedVersions = []uint16{
	VersionTLS13,
	VersionTLS12,
	VersionTLS11,
	VersionTLS10,
}

func (c *Config) supportedVersions() []uint16 {
	versions := make([]uint16, 0, len(supportedVersions))
	for _, v := range supportedVersions {
		if c != nil && c.MinVersion != 0 && v < c.MinVersion {
			continue
		}
		if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
			continue
		}
		versions = append(versions, v)
	}
	return versions
}

func (c *Config) maxSupportedVersion() uint16 {
	supportedVersions := c.supportedVersions()
	if len(supportedVersions) == 0 {
		return 0
	}
	return supportedVersions[0]
}

// supportedVersionsFromMax返回从源代码派生的受支持版本的列表
// 旧版最大版本值。请注意，仅此应用程序支持的版本
// 图书馆被归还了。任何较新的对等机都将使用supportedVersions。
func supportedVersionsFromMax(maxVersion uint16) []uint16 {
	versions := make([]uint16, 0, len(supportedVersions))
	for _, v := range supportedVersions {
		if v > maxVersion {
			continue
		}
		versions = append(versions, v)
	}
	return versions
}

var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}

func (c *Config) curvePreferences() []CurveID {
	if c == nil || len(c.CurvePreferences) == 0 {
		return defaultCurvePreferences
	}
	return c.CurvePreferences
}

func (c *Config) supportsCurve(curve CurveID) bool {
	for _, cc := range c.curvePreferences() {
		if cc == curve {
			return true
		}
	}
	return false
}

// mutualVersion返回给定播发的协议版本以供使用
// 对等版本。优先级被赋予对等优先顺序。
func (c *Config) mutualVersion(peerVersions []uint16) (uint16, bool) {
	supportedVersions := c.supportedVersions()
	for _, peerVersion := range peerVersions {
		for _, v := range supportedVersions {
			if v == peerVersion {
				return v, true
			}
		}
	}
	return 0, false
}

var errNoCertificates = errors.New("tls: no certificates configured")

// getCertificate返回给定ClientHelloInfo的最佳证书，
// 默认为c.Certificates的第一个元素。
func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
	if c.GetCertificate != nil &&
		(len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
		cert, err := c.GetCertificate(clientHello)
		if cert != nil || err != nil {
			return cert, err
		}
	}

	if len(c.Certificates) == 0 {
		return nil, errNoCertificates
	}

	if len(c.Certificates) == 1 {
		// 只有一个选择，所以做任何工作都没有意义。
		return &c.Certificates[0], nil
	}

	if c.NameToCertificate != nil {
		name := strings.ToLower(clientHello.ServerName)
		if cert, ok := c.NameToCertificate[name]; ok {
			return cert, nil
		}
		if len(name) > 0 {
			labels := strings.Split(name, ".")
			labels[0] = "*"
			wildcardName := strings.Join(labels, ".")
			if cert, ok := c.NameToCertificate[wildcardName]; ok {
				return cert, nil
			}
		}
	}

	for _, cert := range c.Certificates {
		if err := clientHello.SupportsCertificate(&cert); err == nil {
			return &cert, nil
		}
	}

	// 如果没有匹配项，则返回第一个证书。
	return &c.Certificates[0], nil
}

// 如果提供的证书受支持，则SupportsCertificate返回nil
// 发送ClientHello的客户端。否则，它将返回一个错误
// 描述不兼容的原因。
// None
// 如果此ClientHelloInfo已传递给GetConfigForClient或GetCertificate
// 回调时，此方法将考虑关联的配置。注意
// 如果GetConfigForClient返回不同的配置，则无法更改
// 用这种方法计算。
// None
// 此函数将调用x509.ParseCertificate，除非设置了c.Leaf，它可以
// 产生巨大的性能成本。
func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
	// 注意：我们目前不支持证书颁发机构，也不支持
	// 签名\u算法\u证书，不检查
	// 链上的签名（无论如何都是a），请参见RFC 8446，
	// 第4.4.2.2节）。

	config := chi.config
	if config == nil {
		config = &Config{}
	}
	vers, ok := config.mutualVersion(chi.SupportedVersions)
	if !ok {
		return errors.New("no mutually supported protocol versions")
	}

	// 如果客户端指定了其尝试连接的名称，则
	// 证书必须对其有效。
	if chi.ServerName != "" {
		x509Cert, err := c.leaf()
		if err != nil {
			return fmt.Errorf("failed to parse certificate: %w", err)
		}
		if err := x509Cert.VerifyHostname(chi.ServerName); err != nil {
			return fmt.Errorf("certificate is not valid for requested server name: %w", err)
		}
	}

	// 如果证书和连接支持，则supportsRSAFallback返回nil
	// 静态RSA密钥交换，否则不受支持。逻辑
	// 支持静态RSA与
	// 支持签名密钥交换，所以我们只是将其作为备用项进行检查。
	supportsRSAFallback := func(unsupported error) error {
		// TLS 1.3放弃了对静态RSA密钥交换的支持。
		if vers == VersionTLS13 {
			return unsupported
		}
		// 静态RSA密钥交换通过使用
		// RSA私钥，而不是通过签名，因此请检查私钥实现
		// 加密解密程序，就像*rsa.PrivateKey一样。
		if priv, ok := c.PrivateKey.(crypto.Decrypter); ok {
			if _, ok := priv.Public().(*rsa.PublicKey); !ok {
				return unsupported
			}
		} else {
			return unsupported
		}
		// 最后，需要一个使用静态密码的互密码套件
		// RSA密钥交换，而不是ECDHE。
		rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
			if c.flags&suiteECDHE != 0 {
				return false
			}
			if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
				return false
			}
			return true
		})
		if rsaCipherSuite == nil {
			return unsupported
		}
		return nil
	}

	// 如果客户端发送了签名算法扩展，请确保它支持
	// 我们可以使用此证书和TLS版本的方案。
	if len(chi.SignatureSchemes) > 0 {
		if _, err := selectSignatureScheme(vers, c, chi.SignatureSchemes); err != nil {
			return supportsRSAFallback(err)
		}
	}

	// 在TLS 1.3中，我们这样做是因为受支持的_组仅与
	// ECDHE计算，删除点格式协商，删除密码套件
	// 仅与AEAD选择相关，静态RSA不存在。
	if vers == VersionTLS13 {
		return nil
	}

	// 我们支持的唯一签名密钥交换是ECDHE。
	if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) {
		return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange"))
	}

	var ecdsaCipherSuite bool
	if priv, ok := c.PrivateKey.(crypto.Signer); ok {
		switch pub := priv.Public().(type) {
		case *ecdsa.PublicKey:
			var curve CurveID
			switch pub.Curve {
			case elliptic.P256():
				curve = CurveP256
			case elliptic.P384():
				curve = CurveP384
			case elliptic.P521():
				curve = CurveP521
			default:
				return supportsRSAFallback(unsupportedCertificateError(c))
			}
			var curveOk bool
			for _, c := range chi.SupportedCurves {
				if c == curve && config.supportsCurve(c) {
					curveOk = true
					break
				}
			}
			if !curveOk {
				return errors.New("client doesn't support certificate curve")
			}
			ecdsaCipherSuite = true
		case ed25519.PublicKey:
			if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 {
				return errors.New("connection doesn't support Ed25519")
			}
			ecdsaCipherSuite = true
		case *rsa.PublicKey:
		default:
			return supportsRSAFallback(unsupportedCertificateError(c))
		}
	} else {
		return supportsRSAFallback(unsupportedCertificateError(c))
	}

	// 确保有一个相互支持的密码套件可用于
	// 这个证书。然后，选择密码套件将在中应用逻辑
	// 倒过来摘。另请参见serverHandshakeState.cipherSuiteOk。
	cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
		if c.flags&suiteECDHE == 0 {
			return false
		}
		if c.flags&suiteECSign != 0 {
			if !ecdsaCipherSuite {
				return false
			}
		} else {
			if ecdsaCipherSuite {
				return false
			}
		}
		if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
			return false
		}
		return true
	})
	if cipherSuite == nil {
		return supportsRSAFallback(errors.New("client doesn't support any cipher suites compatible with the certificate"))
	}

	return nil
}

// 如果提供的证书受支持，则SupportsCertificate返回nil
// 发送CertificateRequest的服务器。否则，它将返回一个错误
// 描述不兼容的原因。
func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error {
	if _, err := selectSignatureScheme(cri.Version, c, cri.SignatureSchemes); err != nil {
		return err
	}

	if len(cri.AcceptableCAs) == 0 {
		return nil
	}

	for j, cert := range c.Certificate {
		x509Cert := c.Leaf
		// 如果这不是叶节点，或者
		// 链。叶是零。
		if j != 0 || x509Cert == nil {
			var err error
			if x509Cert, err = x509.ParseCertificate(cert); err != nil {
				return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err)
			}
		}

		for _, ca := range cri.AcceptableCAs {
			if bytes.Equal(x509Cert.RawIssuer, ca) {
				return nil
			}
		}
	}
	return errors.New("chain is not signed by an acceptable CA")
}

// BuildNameToCertificate解析c.证书并生成c.NameToCertificate
// 从每个叶的CommonName和SubjectAlternateName字段
// 证书。
// None
// 不推荐使用：NameToCertificate仅允许关联单个证书
// 有一个名字。将该字段保留为nil，让库选择第一个
// 来自证书的兼容链。
func (c *Config) BuildNameToCertificate() {
	c.NameToCertificate = make(map[string]*Certificate)
	for i := range c.Certificates {
		cert := &c.Certificates[i]
		x509Cert, err := cert.leaf()
		if err != nil {
			continue
		}
		// 如果SAN不存在，一些客户会考虑证书。
		// 对公用名称中的名称有效。
		if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
			c.NameToCertificate[x509Cert.Subject.CommonName] = cert
		}
		for _, san := range x509Cert.DNSNames {
			c.NameToCertificate[san] = cert
		}
	}
}

const (
	keyLogLabelTLS12           = "CLIENT_RANDOM"
	keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
	keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
	keyLogLabelClientTraffic   = "CLIENT_TRAFFIC_SECRET_0"
	keyLogLabelServerTraffic   = "SERVER_TRAFFIC_SECRET_0"
)

func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
	if c.KeyLogWriter == nil {
		return nil
	}

	logLine := []byte(fmt.Sprintf("%s %x %x\n", label, clientRandom, secret))

	writerMutex.Lock()
	_, err := c.KeyLogWriter.Write(logLine)
	writerMutex.Unlock()

	return err
}

// writerMutex在全球范围内保护所有KeyLogWriter。它很少启用，
// 并且只用于调试，因此全局互斥可以节省空间。
var writerMutex sync.Mutex

// 证书是一个或多个证书的链，首先是叶子。
type Certificate struct {
	Certificate [][]byte
	// PrivateKey包含与中的公钥对应的私钥
	// 叶这必须使用RSA、ECDSA或Ed25519公钥实现加密签名。
	// 对于高达TLS1.2的服务器，它还可以使用
	// RSA公钥。
	PrivateKey crypto.PrivateKey
	// SupportedSignatureAlgorithms是一个可选列表，用于限制
	// 私钥可以用于签名算法。
	SupportedSignatureAlgorithms []SignatureScheme
	// OCSPStaple包含一个可选的OCSP响应，将提供该响应
	// 给提出请求的客户。
	OCSPStaple []byte
	// SignedCertificateTimestamp包含一个可选的已签名证书列表
	// 证书时间戳，将提供给请求它的客户端。
	SignedCertificateTimestamps [][]byte
	// 叶是叶证书的解析形式，可以对其进行初始化
	// 使用x509.ParseCertificate减少每次握手处理。如果为零，
	// 将根据需要解析叶证书。
	Leaf *x509.Certificate
}

// leaf返回解析后的叶证书，可以是来自c.leaf，也可以是通过解析
// 相应的c.证书[0]。
func (c *Certificate) leaf() (*x509.Certificate, error) {
	if c.Leaf != nil {
		return c.Leaf, nil
	}
	return x509.ParseCertificate(c.Certificate[0])
}

type handshakeMessage interface {
	marshal() []byte
	unmarshal([]byte) bool
}

// LRuseSessionCache是一个使用LRU的ClientSessionCache实现
// 缓存策略。
type lruSessionCache struct {
	sync.Mutex

	m        map[string]*list.Element
	q        *list.List
	capacity int
}

type lruSessionCacheEntry struct {
	sessionKey string
	state      *ClientSessionState
}

// NewLRUClientSessionCache返回具有给定
// 使用LRU策略的容量。如果容量小于1，则为默认容量
// 而是使用。
func NewLRUClientSessionCache(capacity int) ClientSessionCache {
	const defaultSessionCacheCapacity = 64

	if capacity < 1 {
		capacity = defaultSessionCacheCapacity
	}
	return &lruSessionCache{
		m:        make(map[string]*list.Element),
		q:        list.New(),
		capacity: capacity,
	}
}

// Put将提供的（sessionKey，cs）对添加到缓存中。如果cs为零，则输入
// 而是从缓存中删除与sessionKey相对应的。
func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
	c.Lock()
	defer c.Unlock()

	if elem, ok := c.m[sessionKey]; ok {
		if cs == nil {
			c.q.Remove(elem)
			delete(c.m, sessionKey)
		} else {
			entry := elem.Value.(*lruSessionCacheEntry)
			entry.state = cs
			c.q.MoveToFront(elem)
		}
		return
	}

	if c.q.Len() < c.capacity {
		entry := &lruSessionCacheEntry{sessionKey, cs}
		c.m[sessionKey] = c.q.PushFront(entry)
		return
	}

	elem := c.q.Back()
	entry := elem.Value.(*lruSessionCacheEntry)
	delete(c.m, entry.sessionKey)
	entry.sessionKey = sessionKey
	entry.state = cs
	c.q.MoveToFront(elem)
	c.m[sessionKey] = elem
}

// Get返回与给定键关联的ClientSessionState值。信息技术
// 如果找不到值，则返回（nil，false）。
func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
	c.Lock()
	defer c.Unlock()

	if elem, ok := c.m[sessionKey]; ok {
		c.q.MoveToFront(elem)
		return elem.Value.(*lruSessionCacheEntry).state, true
	}
	return nil, false
}

var emptyConfig Config

func defaultConfig() *Config {
	return &emptyConfig
}

func unexpectedMessageError(wanted, got interface{}) error {
	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
}

func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
	for _, s := range supportedSignatureAlgorithms {
		if s == sigAlg {
			return true
		}
	}
	return false
}
